#include "mainwindow.h"
#include "ui_mainwindow.h"

Q_DECLARE_METATYPE(AppInfo*)

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    enableUI(false);

    //读取配置文件
    //QSettings settings(this->m_mypath+"/configs.ini",QSettings::IniFormat, this);
    //m_url = settings.value("/smanager/server").toString();

    //初始化右键菜单
    m_rmenu = new QMenu(this);
    m_rmenu->addAction(ui->actionAddApp);
    m_rmenu->addAction(ui->actionDeleteApp);

    ui->lwApps->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->lwApps, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(slotLwContextMenu(QPoint)));

    //默认全部设置为非活动控件
    ui->lwApps->setEnabled(false);
    enableUI(false);

    //后续得想想怎么实现服务器端的状态发生改变时自动通知客户端，大致思路是用订阅，但要想想怎么才能做得更好些
    //暂时就做个刷新按钮替代一下

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::connectToServer(ModelServer info)
{
    if(info.serverDest.contains(':'))
    {
        //包含冒号说明是ipv6地址
        this->m_url = "ws://[" + info.serverDest + "]:" + QString::number(info.serverPort);
    }
    else
    {
        //不包含冒号认为是ipv4地址
        this->m_url = "ws://" + info.serverDest + ":" + QString::number(info.serverPort);
    }
    this->m_userName = info.userName;
    this->m_passWd = info.passWd;

    //初始化websocket
    this->m_whelper = new WSockClientHelper(this);
    connect(m_whelper, SIGNAL(onConnectServer()),
            this, SLOT(slotConnectServer()));
    connect(m_whelper, SIGNAL(onDisconnected()),
            this, SLOT(slotDisconnected()));
    connect(m_whelper, SIGNAL(onError()),
            this, SLOT(slotError()));
    connect(m_whelper, SIGNAL(onReceiveMessage(WSockResponse)),
            this, SLOT(slotOnReceiveMessage(WSockResponse)));
    this->m_whelper->connectToServer(m_url);
}

//设置右侧UI界面是否启用
void MainWindow::enableUI(bool isEnable)
{
    ui->txtAppName->setEnabled(isEnable);
    ui->chkAutoStart->setEnabled(isEnable);
    ui->txtAppPath->setEnabled(isEnable);
    ui->txtArgs->setEnabled(isEnable);
    ui->btnBrowse->setEnabled(isEnable);
    ui->chkAutoRestart->setEnabled(isEnable);
    ui->txtRestartTime->setEnabled(isEnable);
    ui->btnSave->setEnabled(isEnable);
    ui->btnStart->setEnabled(isEnable);
    ui->btnClose->setEnabled(isEnable);
}

//生成显示名称
QString MainWindow::genAppDisplayName(AppInfo *info)
{
    QString res="";
    if(info == nullptr)
        return res;

    res.append(info->name());

    if(info->isRunning())
        res.append(tr(" (运行中)"));
    else
        res.append(tr(" (未运行)"));

    if(info->isSave() == false)
        res.append(tr(" *"));

    return res;
}

//在界面上显示APPInfo的详细信息
void MainWindow::showAppInfo(AppInfo *info)
{
    if(info == nullptr)
        return;

    enableUI(true);
    ui->txtAppName->setText(info->name());
    ui->chkAutoStart->setChecked(info->isAutoStart());
    ui->txtAppPath->setText(info->path());
    ui->txtArgs->setText(info->args());
    ui->chkAutoRestart->setChecked(info->isAutoRestart());
    ui->txtRestartTime->setText(QString::number(info->autoRestartTime()));

    toggleBtnStatus(info);
}

//切换保存、启动、关闭三个按钮的状态
void MainWindow::toggleBtnStatus(AppInfo *info)
{
    if(info == nullptr)
        return;

    //如果未保存，启用保存按钮
    if(info->isSave())
        ui->btnSave->setEnabled(false);
    else
        ui->btnSave->setEnabled(true);

    //如果未运行，启用启动按钮，否则启用关闭按钮
    if(info->isRunning())
    {
        ui->btnStart->setEnabled(false);
        ui->btnClose->setEnabled(true);
    }
    else
    {
        ui->btnStart->setEnabled(true);
        ui->btnClose->setEnabled(false);
    }
}

//Json转AppInfo
AppInfo *MainWindow::convertJsonToAppInfo(QJsonDocument doc)
{
    AppInfo* info = nullptr;
    if(doc.isNull() || doc.isEmpty())
        return info;

    QJsonObject obj = doc.object();
    info = convertJsonToAppInfo(obj);
    return info;
}

//Json转AppInfo
AppInfo *MainWindow::convertJsonToAppInfo(QJsonObject obj)
{
    AppInfo* info = nullptr;
    if(obj.isEmpty())
        return info;

    info = new AppInfo();
    if(obj.contains("Id"))
        info->setId(obj["Id"].toString(""));
    if(obj.contains("Name"))
        info->setName(obj["Name"].toString(""));
    if(obj.contains("IsAutoStart"))
        info->setIsAutoStart(obj["IsAutoStart"].toBool(false));
    if(obj.contains("Path"))
        info->setPath(obj["Path"].toString(""));
    if(obj.contains("Args"))
        info->setArgs(obj["Args"].toString(""));
    if(obj.contains("IsAutoRestart"))
        info->setIsAutoRestart(obj["IsAutoRestart"].toBool(false));
    if(obj.contains("AutoRestartTime"))
        info->setAutoRestartTime(obj["AutoRestartTime"].toInt(30));
    if(obj.contains("IsRunning"))
        info->setIsRunning(obj["IsRunning"].toBool(false));
    return info;
}

//将AppInfo转换为json字符串
QString MainWindow::convertAppInfoToJsonString(AppInfo *info)
{
    QString res;
    if(info == nullptr)
        return res;

    QJsonDocument json;
    QJsonObject jobj;
    jobj.insert("Id", info->id());
    jobj.insert("Name", info->name());
    jobj.insert("IsAutoStart", info->isAutoStart());
    jobj.insert("Path", info->path());
    jobj.insert("Args", info->args());
    jobj.insert("IsAutoRestart", info->isAutoRestart());
    jobj.insert("AutoRestartTime", info->autoRestartTime());

    json.setObject(jobj);
    res = QString::fromUtf8(json.toJson());
    return res;
}

//将map转换为json字符串
QString MainWindow::convertMapToJsonString(QMap<QString, QString> map)
{
    QJsonDocument doc;
    QJsonObject obj;
    foreach(QString key, map.keys())
    {
        obj.insert(key, map[key]);
    }
    doc.setObject(obj);

    return QString::fromUtf8(doc.toJson());
}

//登录返回
void MainWindow::callbackLogin(WSockResponse response)
{
    if(isInit == false)
    {
        isInit = true;

        //获取当前所有的开机自启程序
        m_whelper->callApi("/Api/GetAllApps", "");

        if(ui->lwApps->selectedItems().size()>0)
            enableUI(true);
    }
    else
    {
        //直接刷新
        on_actionRefresh_triggered();
    }
    ui->lwApps->setEnabled(true);
}

//服务器返回所有app列表
void MainWindow::callbackGetAllApps(WSockResponse response)
{
    try {
        if(response.status != 0)
            throw response.err;

        if(response.val.isNull() || response.val.isEmpty())
            return;

        //转Json
        QJsonDocument jdoc = QJsonDocument::fromJson(response.val.toUtf8());
        QJsonArray arr = jdoc.array();
        if(arr.size() <= 0)
            return;

        for(int i=0; i<arr.size(); i++)
        {
            QJsonObject item = arr.at(i).toObject();

            AppInfo* info = convertJsonToAppInfo(item);
            info->setIsSave(true);

            QListWidgetItem* qitem = new QListWidgetItem();
            qitem->setText(genAppDisplayName(info));
            QVariant variant;
            variant.setValue(info);
            qitem->setData(Qt::UserRole, variant);
            ui->lwApps->addItem(qitem);
        }

        if(m_index == -1 || m_index >= ui->lwApps->count())
            ui->lwApps->setCurrentRow(0);
        else
            ui->lwApps->setCurrentRow(m_index);
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//服务器返回，新建自启程序
void MainWindow::callbackAddApp(WSockResponse response)
{
    try {
        if(response.status != 0)
            throw response.err;

        QJsonDocument jdoc = QJsonDocument::fromJson(response.val.toUtf8());
        QJsonObject jroot = jdoc.object();
        QString id = jroot["Id"].toString();

        QListWidgetItem* item =  ui->lwApps->currentItem();

        QVariant value = item->data(Qt::UserRole);
        AppInfo* info = value.value<AppInfo*>();
        if(info != nullptr)
        {
            info->setId(id);
            info->setIsSave(true);
        }

        item->setText(genAppDisplayName(info));
        toggleBtnStatus(info);
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }

    ui->lwApps->setEnabled(true);
}

//程序启动回调
void MainWindow::callbackStartUp(WSockResponse response)
{
    try {
        if(ui->lwApps->count() <= 0)
            return;
        if(response.status != 0)
            throw response.err;

        QJsonDocument doc = QJsonDocument::fromJson(response.val.toUtf8());
        AppInfo* resInfo = convertJsonToAppInfo(doc);
        if(resInfo == nullptr)
            throw tr("服务器未返回结果~");

        //找出启动的程序是哪一个
        for(int i=0; i<ui->lwApps->count(); i++)
        {
            auto item = ui->lwApps->item(i);
            AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
            if(info == nullptr)
                continue;
            if(info->id() != resInfo->id())
                continue;

            info->setIsRunning(resInfo->isRunning());
            item->setText(genAppDisplayName(info));
            if(item == ui->lwApps->currentItem())
                toggleBtnStatus(info);

            break;
        }
        delete resInfo;
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//关闭程序回调
void MainWindow::callbackStopApp(WSockResponse response)
{
    try {
        if(ui->lwApps->count() <= 0)
            return;
        if(response.status != 0)
            throw response.err;

        QJsonDocument doc = QJsonDocument::fromJson(response.val.toUtf8());
        AppInfo* resInfo = convertJsonToAppInfo(doc);
        if(resInfo == nullptr)
            throw tr("服务器未返回结果~");

        //找出关闭的程序是哪一个
        for(int i=0; i<ui->lwApps->count(); i++)
        {
            auto item = ui->lwApps->item(i);
            AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
            if(info == nullptr)
                continue;
            if(info->id() != resInfo->id())
                continue;

            info->setIsRunning(resInfo->isRunning());
            item->setText(genAppDisplayName(info));
            if(item == ui->lwApps->currentItem())
                toggleBtnStatus(info);

            break;
        }
        delete resInfo;
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//服务器返回删除回调
void MainWindow::callbackDeleteApp(WSockResponse response)
{
    try {
        if(ui->lwApps->count() <= 0)
            return;
        if(response.status != 0)
            throw response.err;

        QJsonDocument doc = QJsonDocument::fromJson(response.val.toUtf8());
        AppInfo* resInfo = convertJsonToAppInfo(doc);
        if(resInfo == nullptr)
            throw tr("服务器未返回结果~");

        //找出删除的程序是哪一个
        int index = -1;
        for(int i=0; i<ui->lwApps->count(); i++)
        {
            auto item = ui->lwApps->item(i);
            AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
            if(info == nullptr)
                continue;
            if(info->id() != resInfo->id())
                continue;

            delete info;
            ui->lwApps->takeItem(i);
            delete item;
            index = i;

            break;
        }
        delete resInfo;

        if(ui->lwApps->count() > 0 && index >= 0)
        {
            if(index == ui->lwApps->count())
            {
                //如果之前删除的是最后一个，选中被删除的前一个
                ui->lwApps->setCurrentRow(index - 1);
            }
            else
            {
                //否则选择后面一个
                ui->lwApps->setCurrentRow(index);
            }
        }
        else
        {
            //如果界面上一个App都没有了
            enableUI(false);
        }
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//连接到服务
void MainWindow::slotConnectServer()
{
    //连接成功后调用接口进行认证
    QByteArray bpwd = QCryptographicHash::hash(this->m_passWd.toLatin1(), QCryptographicHash::Md5);
    QString spwd = bpwd.toHex();

    QMap<QString,QString> map;
    map.insert("Username", this->m_userName);
    map.insert("Password", spwd);
    QString p = this->convertMapToJsonString(map);
    qDebug()<<p;

    this->m_whelper->callApi("/Api/Login", p);
}

//连接断开
void MainWindow::slotDisconnected()
{
    ui->lwApps->setEnabled(false);
    enableUI(false);
    if(QMessageBox::question(this,tr("提示"),tr("连接断开，是否重连？")) == QMessageBox::Ok)
    {
        m_whelper->connectToServer(m_url);
    }
}

//连接错误
void MainWindow::slotError()
{
    ui->lwApps->setEnabled(false);
    enableUI(false);
    QMessageBox::critical(this, tr("错误"),
                          tr("连接错误，正在重连~"));
    m_whelper->connectToServer(m_url);
}

//收到服务数据
void MainWindow::slotOnReceiveMessage(WSockResponse response)
{
    if(response.topic == "/Api/Login")
    {
        //登录
        callbackLogin(response);
    }
    if(response.topic == "/Api/GetAllApps")
    {
        //服务端返回所有开机自启程序
        callbackGetAllApps(response);
    }
    else if(response.topic == "/Api/AddApp")
    {
        //服务端返回添加自启程序结果
        callbackAddApp(response);
    }
    else if(response.topic == "/Api/StartApp")
    {
        //服务端返回程序启动结果
        callbackStartUp(response);
    }
    else if(response.topic == "/Api/StopApp")
    {
        //服务器返回程序停止结果
        callbackStopApp(response);
    }
    else if(response.topic == "/Api/DeleteApp")
    {
        //服务器返回删除自启程序结果
        callbackDeleteApp(response);
    }
}

//列表框右键菜单
void MainWindow::slotLwContextMenu(QPoint)
{
    if(ui->lwApps->selectedItems().size()>0)
    {
        ui->actionDeleteApp->setEnabled(true);
    }
    else
    {
        ui->actionDeleteApp->setDisabled(true);
    }
    m_rmenu->exec(QCursor::pos());
}

//添加（右键菜单）
void MainWindow::on_actionAddApp_triggered()
{
    AppInfo* info = new AppInfo();
    info->setName(tr("新建自启程序"));
    info->setIsAutoStart(true);
    info->setPath("");
    info->setArgs("");
    info->setIsAutoRestart(true);
    info->setAutoRestartTime(30);
    info->setIsRunning(false);
    info->setIsSave(false);

    QListWidgetItem* item = new QListWidgetItem();
    item->setText(genAppDisplayName(info));
    QVariant variant;
    variant.setValue(info);
    item->setData(Qt::UserRole, variant);
    ui->lwApps->addItem(item);

    ui->lwApps->setCurrentItem(item);
}

//列表选中项修改
void MainWindow::on_lwApps_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    if(current == nullptr)
    {
        enableUI(false);
        return;
    }

    AppInfo* info = current->data(Qt::UserRole).value<AppInfo*>();
    showAppInfo(info);
}

//修改名称
void MainWindow::on_txtAppName_textChanged(const QString &arg1)
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    info->setName(arg1);

    QString title = genAppDisplayName(info);
    item->setText(title);
    toggleBtnStatus(info);
}

//修改是否自动启动状态
void MainWindow::on_chkAutoStart_stateChanged(int arg1)
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    info->setIsAutoStart(ui->chkAutoStart->isChecked());

    QString title = genAppDisplayName(info);
    item->setText(title);
    toggleBtnStatus(info);
}

//修改程序路径
void MainWindow::on_txtAppPath_textChanged(const QString &arg1)
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    info->setPath(arg1);

    QString title = genAppDisplayName(info);
    item->setText(title);
    toggleBtnStatus(info);
}

//修改启动参数
void MainWindow::on_txtArgs_textChanged(const QString &arg1)
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    info->setArgs(arg1);

    QString title = genAppDisplayName(info);
    item->setText(title);
    toggleBtnStatus(info);
}

//修改关闭后是否自动重启
void MainWindow::on_chkAutoRestart_stateChanged(int arg1)
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    info->setIsAutoRestart(ui->chkAutoRestart->isChecked());

    QString title = genAppDisplayName(info);
    item->setText(title);
    toggleBtnStatus(info);
}

//修改自动重启时间
void MainWindow::on_txtRestartTime_textChanged(const QString &arg1)
{
    try {
        QListWidgetItem* item = ui->lwApps->currentItem();
        if(item == nullptr)
            return;
        if(arg1.isNull() || arg1.isEmpty())
            return;

        bool isOk = false;
        int sec = 0;
        sec = arg1.toInt(&isOk);
        if(isOk == false)
            throw tr("无效的数字~");
        if(sec < 0)
            throw tr("自动重启时间间隔必须大于等于0~");

        AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
        info->setAutoRestartTime(sec);

        QString title = genAppDisplayName(info);
        item->setText(title);
        toggleBtnStatus(info);
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

/* 浏览自启程序路径
 * 由于管理程序是支持远程的，所以后续可以自定义一个远程服务器的文件打开对话框
 * 第一版本只做本地的，管理程序放在服务器上运行，或者直接拷贝服务器的自启程序
 * 路径到文本框中。
 * */
void MainWindow::on_btnBrowse_clicked()
{
    try {
        QFileDialog* dia = new QFileDialog(this, tr("打开"), "",
                                           "全部文件(*.*);;可执行程序文件(*.exe)");
        if(dia->exec() == QDialog::Accepted)
        {
            //可能会有一些意想不到的东西需要运行，所以就不判断后缀了
            ui->txtAppPath->setText(dia->selectedFiles()[0]);
        }
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//保存当前选中项
void MainWindow::on_btnSave_clicked()
{
    try {
        QListWidgetItem* item = ui->lwApps->currentItem();
        if(item == nullptr)
            return;

        AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
        if(info->name().isNull() || info->name().isEmpty())
            throw tr("名称不能为空~");
        if(info->path().isNull() || info->path().isEmpty())
            throw tr("程序路径不能为空~");

        //通知服务端处理
        QString p = convertAppInfoToJsonString(info);
        m_whelper->callApi("/Api/AddApp", p);
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

//启动程序
void MainWindow::on_btnStart_clicked()
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    qDebug()<<info->id();
    m_whelper->callApi("/Api/StartApp", info->id());
}

//停止程序
void MainWindow::on_btnClose_clicked()
{
    QListWidgetItem* item = ui->lwApps->currentItem();
    if(item == nullptr)
        return;

    AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
    m_whelper->callApi("/Api/StopApp", info->id());
}

//刷新
void MainWindow::on_actionRefresh_triggered()
{
    //记录下来当前选中行
    this->m_index = ui->lwApps->currentRow();

    //删除现有项
    while (ui->lwApps->count() > 0) {
        auto item = ui->lwApps->takeItem(0);
        delete item->data(Qt::UserRole).value<AppInfo*>();
    }

    m_whelper->callApi("/Api/GetAllApps", "");
}

//删除启动程序
void MainWindow::on_actionDeleteApp_triggered()
{
    try {
        if(QMessageBox::question(this, tr("确认"), tr("确定要删除选中项吗~")) == QMessageBox::Yes)
        {
            auto item = ui->lwApps->currentItem();
            if(item == nullptr)
                throw tr("请选择要删除的程序~");

            AppInfo* info = item->data(Qt::UserRole).value<AppInfo*>();
            if(info == nullptr)
                throw tr("未取到程序信息~");

            m_whelper->callApi("/Api/DeleteApp", info->id());
        }
    } catch (QString strEx) {
        QMessageBox::critical(this, tr("错误"), strEx);
    }
}

